package com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.repository;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageHelper;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.FlowExecutionQueryService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.RemindCheckService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.UserService;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.FlowUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.client.HttpFlowQueryInfoDto;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.NodeAuthEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowExecutionQueryInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowReNodeAuthVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.User;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.FlowExecutionQueryVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import com.iwhalecloud.citybrain.flow.platform.manager.infrastructure.mapper.FlowExecutionQueryDAO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.FlowElement;
import org.flowable.bpmn.model.Process;
import org.flowable.editor.language.json.converter.util.CollectionUtils;
import org.flowable.engine.RepositoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author lilh
 * @date 2019-01-24 15:14
 */
@Service
@Slf4j
public class FlowExecutionQueryServiceImpl implements FlowExecutionQueryService {

    @Value("${busi.approvalPage:/assignment/biz/service/instance/wf/todo}")
    private String busiApprovalPage;


    @Autowired
    private FlowExecutionQueryDAO flowExecutionQueryDAO;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private RemindCheckService remindCheckService;

    @Autowired
    private FlowTaskTraceRepository taskTraceRepository;

    @Autowired
    private FlowReNodeAuthRepository nodeAuthService;

    @Autowired
    private UserService userService;

    @Autowired
    private FlowMonitorRepository flowMonitorRepository;

    @Autowired
    private FlowTaskTraceRepository flowTaskTraceRepository;

    @Autowired
    FlowTitleExpressionResultRepository flowTitleExpressionResultRepository;


    @Override
    public List<FlowExecutionQueryInfo> todoTasks(FlowExecutionQueryVo flowExecutionQueryVo) {
        User user = userRepository.getCurrentUser();
        PageHelper.startPage(flowExecutionQueryVo.getPageNum(), flowExecutionQueryVo.getPageSize(), true);
        resolveExecutionQuery(flowExecutionQueryVo);
        flowExecutionQueryVo.setAssignee(user.getUserCode());
        flowExecutionQueryVo.setCandidateUser(user.getUserCode());
        if (Objects.nonNull(user.getOrgCode())) {
            String[] split = user.getOrgCode().split(",");
            flowExecutionQueryVo.setCandidateGroup(Arrays.asList(split));
        } else {
            //为了兼容查询条件，这里传一个不存在的候选组，最终SQL中这是个or条件
            flowExecutionQueryVo.setCandidateGroup(Arrays.asList("_notexists"));
        }

        // 设置新扩展的类型
        this.convertToFlowExecutionQueryVo(flowExecutionQueryVo, user);
        List<FlowExecutionQueryInfo> flowExecutionQueryInfos = flowExecutionQueryDAO.todoTasks(flowExecutionQueryVo);
        resolveRollbackAction(flowExecutionQueryInfos);
        resolveBusiApprovalPage(flowExecutionQueryInfos);
        return flowExecutionQueryInfos;
    }

    @Override
    public List<HttpFlowQueryInfoDto> todoTasksByModelKey(HttpFlowQueryInfoDto httpFlowQueryInfoDto) {
        if(httpFlowQueryInfoDto.getPageNum() != null && httpFlowQueryInfoDto.getPageSize() != null){
            PageHelper.startPage(httpFlowQueryInfoDto.getPageNum(), httpFlowQueryInfoDto.getPageSize(), true);
        }
        List<HttpFlowQueryInfoDto> flowExecutionQueryInfos = flowExecutionQueryDAO.todoTasksByModelKey(httpFlowQueryInfoDto);
        resolveRollbackAndApproval(flowExecutionQueryInfos);
        return flowExecutionQueryInfos;
    }

    private void resolveBusiApprovalPage(List<FlowExecutionQueryInfo> flowExecutionQueryInfos) {
        for (FlowExecutionQueryInfo flowExecutionQueryInfo : flowExecutionQueryInfos) {
            StringBuilder sbf = new StringBuilder(busiApprovalPage);
            if (busiApprovalPage.contains("?")){
                sbf.append("&");
            }else {
                sbf.append("?");
            }
            sbf.append("processInstanceId=").append(flowExecutionQueryInfo.getProcessInstanceId())
                    .append("&entityId=").append(flowExecutionQueryInfo.getTaskId());
            flowExecutionQueryInfo.setBusiApprovalPage(sbf.toString());
        }
    }

    private void resolveRollbackAndApproval(List<HttpFlowQueryInfoDto> flowExecutionQueryInfos) {
        for (HttpFlowQueryInfoDto entity : flowExecutionQueryInfos) {
            if (entity.getCanRollback()) {
                Process mainProcess = repositoryService.getBpmnModel(entity.getProcessDefinitionId()).getMainProcess();
                List<FlowElement> flowElementBeforeCurrentElement = FlowUtils.getInstance().getFlowElementBeforeCurrentElement(mainProcess, entity.getTaskDefKey());
                entity.setCanRollback(CollectionUtils.isNotEmpty(flowElementBeforeCurrentElement));
            }
            //自定义标题
            entity.setCustomTitle(flowTitleExpressionResultRepository.getTitleExpressionResultByProcessInstanceIdAndActivityId(entity.getProcessInstanceId(),entity.getTaskDefKey()));
            StringBuilder sbf = new StringBuilder(busiApprovalPage);
            if (busiApprovalPage.contains("?")){
                sbf.append("&");
            }else {
                sbf.append("?");
            }
            sbf.append("processInstanceId=").append(entity.getProcessInstanceId()).append("&entityId=").append(entity.getTaskId());
            entity.setBusiApprovalPage(sbf.toString());
            if(StringUtils.isEmpty(entity.getOperator())){
                entity.setOperator(flowMonitorRepository.getOperatorName(entity.getTaskId()));
            }
        }
    }


    /**
     * 设置新扩展的类型
     *
     * @param flowExecutionQueryVo
     * @param user
     */
    private void  convertToFlowExecutionQueryVo(FlowExecutionQueryVo flowExecutionQueryVo, User user) {
        // 根据用户id获取该用户所属的群组集合和用户对应的岗位集合
        if(StringUtils.isNotBlank(user.getUserCode())) {
            // 获取用户对象信息
            User userInfo = userService.getFullUserInfo(user.getUserCode());
            if (Objects.isNull(userInfo)){
                log.warn("无法查询到用户（id：{}）", user.getUserCode());
                return;
            }

            // 用户角色集合
            flowExecutionQueryVo.setCandidateUserOrg(flowTaskTraceRepository.resolveUserInfo(userInfo, "ORG"));

            // 用户组织集合
            flowExecutionQueryVo.setCandidateUserRole(flowTaskTraceRepository.resolveUserInfo(userInfo, "ROLE"));

            // 用户组信息集合
            flowExecutionQueryVo.setCandidateUserGroup(flowTaskTraceRepository.resolveUserInfo(userInfo, "GROUP"));

            // 用户岗位信息集合
            flowExecutionQueryVo.setCandidateUserPosition(flowTaskTraceRepository.resolveUserInfo(userInfo, "POSITION"));
        }
    }

    private void resolveRollbackAction(List<FlowExecutionQueryInfo> flowExecutionQueryInfos) {
        for (FlowExecutionQueryInfo entity : flowExecutionQueryInfos) {
            //当sql中初步判定为能退回时，再进一步检测
            if (entity.getCanRollback()) {
                Process mainProcess = repositoryService.getBpmnModel(entity.getProcessDefinitionId()).getMainProcess();
                List<FlowElement> flowElementBeforeCurrentElement = FlowUtils.getInstance().getFlowElementBeforeCurrentElement(mainProcess, entity.getTaskDefKey());
                entity.setCanRollback(CollectionUtils.isNotEmpty(flowElementBeforeCurrentElement));
            }
            //自定义标题
            entity.setCustomTitle(flowTitleExpressionResultRepository.getTitleExpressionResultByProcessInstanceIdAndActivityId(entity.getProcessInstanceId(),entity.getTaskDefKey()));
        }
    }

    @Override
    public List<FlowExecutionQueryInfo> processedProcessInstance(FlowExecutionQueryVo flowExecutionQueryVo) {
        User user = userRepository.getCurrentUser();
        PageHelper.startPage(flowExecutionQueryVo.getPageNum(), flowExecutionQueryVo.getPageSize(), true);
        resolveExecutionQuery(flowExecutionQueryVo);
        flowExecutionQueryVo.setAssignee(user.getUserCode());
        return flowExecutionQueryDAO.processedProcessInstance(flowExecutionQueryVo);
    }

    @Override
    public List<FlowExecutionQueryInfo> launchedProcessInstance(FlowExecutionQueryVo flowExecutionQueryVo) {
        User user = userRepository.getCurrentUser();
        PageHelper.startPage(flowExecutionQueryVo.getPageNum(), flowExecutionQueryVo.getPageSize(), true);
        resolveExecutionQuery(flowExecutionQueryVo);
        flowExecutionQueryVo.setApplyUserId(user.getUserCode());
        List<FlowExecutionQueryInfo> flowExecutionQueryInfos = flowExecutionQueryDAO.launchedProcessInstance(flowExecutionQueryVo);
        return getFlowExecutionQueryInfos(user, flowExecutionQueryInfos);
    }

    @Override
    public List<FlowExecutionQueryInfo> getProcessInstanceList(FlowExecutionQueryVo flowExecutionQueryVo) {
        // 分页参数
        PageHelper.startPage(flowExecutionQueryVo.getPageNum(), flowExecutionQueryVo.getPageSize(), true);
        // 获取流程实例数据列表
        return flowExecutionQueryDAO.getProcessInstanceList(flowExecutionQueryVo);
    }

    @Override
    public List<FlowExecutionQueryInfo> getSingleProcessInstanceList(FlowExecutionQueryVo flowExecutionQueryVo) {
        // 分页参数
        PageHelper.startPage(flowExecutionQueryVo.getPageNum(), flowExecutionQueryVo.getPageSize(), true);
        // 获取流程实例数据列表
        List<FlowExecutionQueryInfo> flowExecutionQueryInfos=flowExecutionQueryDAO.getSingleProcessInstanceList(flowExecutionQueryVo);
        // 补全设置流程发起人
        for (FlowExecutionQueryInfo info : flowExecutionQueryInfos) {
            if (Objects.nonNull(info) && StringUtils.isEmpty(info.getApplyUserName()) && StringUtils.isNotBlank(info.getApplyUserId())) {
                // 根据userId获取员工工号
                UserInfo startUserInfo = userService.getUserInfoObj(info.getApplyUserId());
                info.setApplyUserName(startUserInfo == null ? null : startUserInfo.getUserName());
            }
        }
        return flowExecutionQueryInfos;
    }

    @Override
    public int countTodo() {
        User user = userRepository.getCurrentUser();
        FlowExecutionQueryVo flowExecutionQueryVo = new FlowExecutionQueryVo();
        flowExecutionQueryVo.setAssignee(user.getUserCode());
        flowExecutionQueryVo.setCandidateUser(user.getUserCode());
        if (Objects.nonNull(user.getOrgCode())) {
            String[] split = user.getOrgCode().split(",");
            flowExecutionQueryVo.setCandidateGroup(Arrays.asList(split));
        }
        return flowExecutionQueryDAO.todoCount(flowExecutionQueryVo);
    }

    @Override
    public int countProcessed() {
        User user = userRepository.getCurrentUser();
        FlowExecutionQueryVo flowExecutionQueryVo = new FlowExecutionQueryVo();
        flowExecutionQueryVo.setAssignee(user.getUserCode());
        return flowExecutionQueryDAO.countProcessed(flowExecutionQueryVo);
    }

    @Override
    public int countLaunchedProcess() {
        User user = userRepository.getCurrentUser();
        FlowExecutionQueryVo flowExecutionQueryVo = new FlowExecutionQueryVo();
        flowExecutionQueryVo.setApplyUserId(user.getUserCode());
        return flowExecutionQueryDAO.countLaunchedProcess(flowExecutionQueryVo);
    }

    private void resolveExecutionQuery(FlowExecutionQueryVo flowExecutionQueryVo) {
        //flowExecutionQueryVo.setTimeStart(DateUtils.startTimeFormatter(flowExecutionQueryVo.getTimeStart()));
        //flowExecutionQueryVo.setTimeEnd(DateUtils.endTimeFormatter(flowExecutionQueryVo.getTimeEnd()));
    }

    private List<FlowExecutionQueryInfo> getFlowExecutionQueryInfos(User user, List<FlowExecutionQueryInfo> flowExecutionQueryInfos) {
        resolveCurrentTask(flowExecutionQueryInfos, user);
        return flowExecutionQueryInfos;
    }

    private void resolveCurrentTask(List<FlowExecutionQueryInfo> processedProcessInstances, User user) {
        for (FlowExecutionQueryInfo info : processedProcessInstances) {
            if (Objects.nonNull(info.getEndTime())) {
                //流程已完成 20190523
                info.setTaskName("---");
                info.setAssignee(0);
                info.setCanRemind(false);
                info.setCanRecall(false);
            } else {
                info.setAssignee(0);
                //没结束
                //处理撤回，催办按钮权限
                List<FlowTaskTraceVo> runningTasks = taskTraceRepository.listRunningTaskTraces(info.getProcessInstanceId());

                this.resolveRemindAndRecallTag(info, runningTasks, user);
                //info.setCanRemind(!remindCheckService.hasRemindTag(info.getProcessInstanceId()));
            }

        }
    }

    private void resolveRemindAndRecallTag(FlowExecutionQueryInfo baseInfo, List<FlowTaskTraceVo> runningTasks, User current) {
        if (CollectionUtil.isEmpty(runningTasks)
                || !Objects.equals(current.getUserCode(), baseInfo.getApplyUserId())) {
            //没有运行中的任务，说明流程已经结束了，则不可撤回，也不可催办
            //当前登录人不是流程发起人，则无权限操作
            baseInfo.setCanRecall(false);
            baseInfo.setCanRemind(false);
            return;
        }


        for (FlowTaskTraceVo task : runningTasks) {
            //获取任务节点上的配置信息，只要找到有一个配置是开启的，则开启
            List<FlowReNodeAuthVo> nodeAuthList = nodeAuthService.listNodeAuthByProcdefIdAndNodeCode(baseInfo.getProcessDefinitionId(), task.getActivityId());
            Map<String, Boolean> authMap = nodeAuthList.stream().collect(Collectors.toMap(FlowReNodeAuthVo::getAuthName, FlowReNodeAuthVo::getAuthSwitch));
            Boolean canRecall = authMap.getOrDefault(NodeAuthEnum.CALLBACK.getCode(), false);
            if (canRecall) {
                baseInfo.setCanRecall(true);
            }
            Boolean canRemind = authMap.getOrDefault(NodeAuthEnum.REMIND.getCode(), false);
            if (canRemind) {
                baseInfo.setCanRemind(true);
            }
            if (baseInfo.isCanRecall() && baseInfo.isCanRemind()) {
                break;
            }
        }
        if (baseInfo.isCanRemind()) {
            //看看今天是否已经催办过。。。
            baseInfo.setCanRemind(!remindCheckService.hasRemindTag(baseInfo.getProcessInstanceId()));
        }
    }
}
